package com.swim.session;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.jboss.ejb3.annotation.LocalBinding;
import org.jboss.ejb3.annotation.RemoteBinding;
import com.swim.entity.RegisteredUser;
import com.swim.entity.Skill;

@Stateless
@RemoteBinding(jndiBinding="RegisteredUserBeanJNDI")
@LocalBinding(jndiBinding="RegisteredUserBeanLocalJNDI")
public class RegisteredUserBean implements RegisteredUserLocal,RegisteredUserRemote {

	@PersistenceContext(unitName = "SWIM")
	EntityManager database;
	
	/**
	 * @param name the name of the user
	 * @param surname the surname of the user
	 * @return the list of users selected by the name
	 */
	public List<RegisteredUser> getUsersByName(String name, String surname) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
		try {
    		Query q = database.createQuery("SELECT r FROM RegisteredUser r WHERE r.name=:name AND r.surname=:surname");
    		q.setParameter("name", name);
    		q.setParameter("surname", surname);
    		List<?> results =  q.getResultList();
    		for(Object obj: results) {
    			users.add((RegisteredUser) obj);
    		}
    		
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF4");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF5");
    	}
		return users;
	}

	/**
	 * @param skillName the name of the skill
	 * @return the list of users who have the skill
	 */
	public List<RegisteredUser> getUsersBySkill(String skillName) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
		try {
    		Query q = database.createQuery("SELECT r FROM Skill as s, IN (s.users) r WHERE s.name = :skillName");
    		q.setParameter("skillName", skillName);
    		List<RegisteredUser> risultato = (List<RegisteredUser>) q.getResultList();
    		for(RegisteredUser obj: risultato) {
    			obj.getName();
    			users.add(obj);
    		}
    		
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF4");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF5");
    	}
    	return users;
	}

	/**
	 * @param city the name of the city
	 * @return the list of users who live in this city
	 */
	public List<RegisteredUser> getUsersByCity(String city) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
		try {
    		Query q = database.createQuery("SELECT r FROM RegisteredUser r WHERE r.city=:city");
    		q.setParameter("city", city);
    		List<RegisteredUser> risultato = (List<RegisteredUser>) q.getResultList();
    		users.addAll(risultato);
    		
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF4");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF5");
    	}
    	return users;
	}

	/**
	 * @param email the email of an user
	 * @return the user who have this email
	 */
	public RegisteredUser getUserWithEmail(String email) {
    	try {
    		Query q = database.createQuery("SELECT r FROM RegisteredUser r WHERE r.email=:email");
    		q.setParameter("email",email);
    		return (RegisteredUser) q.getSingleResult();
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF1");
    	} catch (javax.persistence.NoResultException exc) { 
    		System.err.println("UFF2");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF3");
    	}
    	return null;
	}

	/**
	 * @param email the email of an user
	 * @return the list of friends of the user
	 */
	public List<RegisteredUser> getFriendsOf(String email) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
		try {
			//TODO: aggiustare sta schifezza di query
    		Query q = database.createQuery("SELECT r FROM RegisteredUser as l, IN (l.friends) r WHERE l.email = :email");
    		q.setParameter("email", email);
    		users = (List<RegisteredUser>) q.getResultList();
    		q = database.createQuery("SELECT r FROM RegisteredUser as l, IN (l.friends1) r WHERE l.email = :email");
    		q.setParameter("email", email);
    		users.addAll((List<RegisteredUser>)q.getResultList());
    		
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF4");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF5");
    	}
    	return users;
	}

	/**
	 * @param email the email of the user
	 * @param name the name of an user
	 * @param surname the surname of the user
	 * @return the list of friends selected by name
	 */
	public List<RegisteredUser> getFriendsByName(String email, String name, String surname) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
		try {
			//TODO: aggiustare sta schifezza di query
    		Query q = database.createQuery("SELECT r FROM RegisteredUser as l, IN (l.friends) r WHERE l.email = :email AND r.name = :name AND r.surname = :surname");
    		q.setParameter("email", email);
    		q.setParameter("name", name);
    		q.setParameter("surname", surname);
    		users = (List<RegisteredUser>) q.getResultList();
    		q = database.createQuery("SELECT r FROM RegisteredUser as l, IN (l.friends1) r WHERE l.email = :email AND r.name = :name AND r.surname = :surname");
    		q.setParameter("email", email);
    		q.setParameter("name", name);
    		q.setParameter("surname", surname);
    		users.addAll((List<RegisteredUser>)q.getResultList());
    		
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF4");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF5");
    	}
    	return users;
	}

	/**
	 * @param email the email of the user
	 * @param skillName the name of the skill
	 * @return the list of friends selected by skill
	 */
	public List<RegisteredUser> getFriendsBySkill(String email, String skillName) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
	try {
		List<RegisteredUser> friends = new ArrayList<RegisteredUser>();
		friends = this.getFriendsOf(email);
		
		List<RegisteredUser> usersWithSkill = new ArrayList<RegisteredUser>();
		usersWithSkill = this.getUsersBySkill(skillName);
		
		for(RegisteredUser friend : friends) {
				if(usersWithSkill.contains(friend)) {
					users.add(friend);
				}
		}
		
	} catch (EntityNotFoundException exc) { 
		System.err.println("UFF1");
	} catch (NonUniqueResultException exc) {
		System.err.println("UFF2");
	}
	return users;
	}

	/**
	 * @param email the email of the user
	 * @param city the name of the city
	 * @return the list of friends selected by city
	 */
	public List<RegisteredUser> getFriendsByCity(String email, String city) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
	try {
		List<RegisteredUser> friends = new ArrayList<RegisteredUser>();
		friends = this.getFriendsOf(email);
		for(RegisteredUser friend : friends) {
			if(friend.getCity().equals(city)) {
				users.add(friend);
			}
		}
		
		
	} catch (EntityNotFoundException exc) { 
		System.err.println("UFF1");
	} catch (NonUniqueResultException exc) {
		System.err.println("UFF2");
	}
	return users;
	}

	/**
	 * @param email the email of the user
	 * @param password the password of the user
	 * @param name the name of the user
	 * @param surname the surname of the user
	 * @param city the city of the user
	 * @param avatar the avatar of the user
	 * @return the outcome of the addition
	 */
	public boolean addUser(String email, String password, String name,
			String surname, String city) {
		try {
    		RegisteredUser user = new RegisteredUser(email, password, false, name, surname, city);
    		database.persist(user);
    		return true;
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF1");
    	} catch (javax.persistence.NoResultException exc) { 
    		System.err.println("UFF2");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF3");
    	}
		return false;
	}
	
	/**
	 * @return the admin
	 */
	public RegisteredUser getAdmin() {
		try {
    		Query q = database.createQuery("SELECT r FROM RegisteredUser r WHERE r.admin='1'");
    		return (RegisteredUser) q.getSingleResult();
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF1");
    	} catch (javax.persistence.NoResultException exc) { 
    		System.err.println("UFF2");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF3");
    	}
    	return null;
	}
	
	/**
	 * @param email the email of the user
	 * @param password the password of the user
	 * @param name the name of the user
	 * @param surname the surname of the user
	 * @param city the city of the user
	 * @param avatar the avatar of the user
	 * @return the outcome of the edit
	 */
	public boolean editUser(String email, String password, String name, String surname, String city) {
		try {
			RegisteredUser user = this.getUserWithEmail(email);
			
			if(!password.equals("")) {
				user.setPassword(password);
			}
			if(!name.equals("")) {
				user.setName(name);
			}
			if(!surname.equals("")) {
				user.setSurname(surname);
			}
			if(!city.equals("")) {
				user.setCity(city);
			}
			
			database.persist(user);
			return true;
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF1");
    	} catch (javax.persistence.NoResultException exc) { 
    		System.err.println("UFF2");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF3");
    	}
    	return false;
	}
	
	/**
	 * @param id the list of skill's id
	 * @param emailUser the email of the user
	 */
	public void addSkill(String[] id, String emailUser) {
		Query q = database.createQuery("SELECT u FROM RegisteredUser u WHERE u.email=:email");
		q.setParameter("email", emailUser);
		RegisteredUser user = (RegisteredUser)q.getSingleResult();
		user.getUserSkills().clear();
		for(String idSkill : id) {
			q = database.createQuery("SELECT s FROM Skill s WHERE s.id=:id");
			q.setParameter("id", Integer.parseInt(idSkill));
			Skill s = (Skill)q.getSingleResult();
			user.getUserSkills().add(s);
		}
	}
	
	/**
	 * @param email the email of the user
	 * @return says if the user has been removed
	 */
	public boolean removeUserWithEmail(String email) {
		RegisteredUser u = this.getUserWithEmail(email);
		if(u != null) {
			database.remove(u);
			return true;
		}
		return false;
	}
	
	/**
	 * @return the local interface of friendship
	 */
	private FriendshipLocal getFriendshipLocal() {
		InitialContext jndiContext;
		Object ref = null;
		try {
			jndiContext = new InitialContext();
			ref = jndiContext.lookup("FriendshipBeanLocalJNDI");
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return (FriendshipLocal) ref;
	}
	
	/**
	 * @param viaEmail the email of the user
	 * @param forEmail the email of the user
	 * @return list of user as suggestion of friendship
	 */
	public List<RegisteredUser> getSuggestions(String forEmail, String viaEmail) {
		List<RegisteredUser> users = new ArrayList<RegisteredUser>();
		try {
			users = getFriendsOf(viaEmail);
			List<RegisteredUser> alreadyFriends = getFriendsOf(forEmail);
			users.removeAll(alreadyFriends);
			users.remove(getUserWithEmail(forEmail));
			
			FriendshipLocal f = getFriendshipLocal();
			users.remove(f.getFriendshipRequestsUsers(forEmail));
    		
    	} catch (EntityNotFoundException exc) { 
    		System.err.println("UFF4");
    	} catch (NonUniqueResultException exc) {
    		System.err.println("UFF5");
    	}
    	return users;
	}

	/**
	 * @param email the email of the user
	 * @result the list of notifications
	 */
	public List<RegisteredUser> getNotifications(String email) {
		RegisteredUser user = getUserWithEmail(email);
		Set<RegisteredUser> notifs = user.getReceivedNotifications();
		List<RegisteredUser> result = new ArrayList<RegisteredUser>();
		result.addAll(notifs);
		return result;
	}

	public void deleteNotification(String toEmail, String viaEmail) {
		getUserWithEmail(toEmail).getReceivedNotifications().remove(getUserWithEmail(viaEmail));
	}
}
